<script setup lang="ts">
import { useRouter } from 'vue-router';

import * as monaco from 'monaco-editor';
import { computed, onMounted, onUnmounted, reactive, ref, defineComponent } from 'vue';
import { Splitpanes, Pane } from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';
import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
import CssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker';
import HtmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker';
import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
import { getProblemById, getSubmissionById, getSubmissionList, Problem, submit } from '@/api/problem';
import { CODE_LANGUAGES, PROBLEM_TABS_KEYS } from '@/const/app';
import SubmitList from '@/components/SubmitList/index.vue';
import SubmitResult from '@/components/SubmitResult/index.vue';
import 'katex/dist/katex.css';

import {
  getContestById,
  getContestProblem,
  getContestSubmissionById,
  getContestSubmissionList,
  submitContestProblem,
} from '@/api/contest';
import Storage from '@/utils/storage';

/**
 * 左侧题目描述显示区
 *  Markdown-it做转换
 */
import MarkdownIt from 'markdown-it';
import { parseTime } from '@/utils/parser';

import { useToast } from 'vue-toast-notification';
import 'vue-toast-notification/dist/theme-sugar.css';
import '@/views/Problem/index.vue';
import { message } from 'ant-design-vue';
import katex from 'katex';
import Vditor from 'vditor';
import 'vditor/dist/index.css';
import md from '@/utils/markdown';


const problemContent = ref('');
const setProblemContent = (origin: string) => {
  origin = origin.replace(/\$\$\$/g, '$');

  // problemContent.value = md.render(origin);
  // // problemContent.value = origin;
  // const renderedText = katex.renderToString(origin, {
  //   throwOnError: false
  // });
  // return origin;
  return md.render(origin);
};

const router = useRouter();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
self.MonacoEnvironment = {
  getWorker(_: any, label: string) {
    if (label === 'json') {
      return new JsonWorker();
    }
    if (label === 'css' || label === 'scss' || label === 'less') {
      return new CssWorker();
    }
    if (label === 'html' || label === 'handlebars' || label === 'razor') {
      return new HtmlWorker();
    }
    if (label === 'typescript' || label === 'javascript') {
      return new TsWorker();
    }
    return new EditorWorker();
  },
};
let editor: monaco.editor.IStandaloneCodeEditor;
const problemId = ref(0);
const contestId = ref(0);
const problemNumber = ref(0);
const contest = reactive<any>({});
const fetchContest = async () => {
  const res = await getContestById(contestId.value);
  console.log(res);
  Object.assign(contest, res);
};

const canSubmit = computed(() => {
  const now = Date.now();
  if (contestId.value) return now > contest.beginTime && now < contest.endTime;
  else return true;
});
onMounted(() => {
  problemId.value = Number(router.currentRoute.value.params.problemId);
  contestId.value = Number(router.currentRoute.value.params.contestId);
  problemNumber.value = Number(router.currentRoute.value.params.problemNumber);
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  editor = monaco.editor.create(document.getElementById('container'), {
    // eslint-disable-next-line max-len
    value: Storage.getLocalItem(`code_${contestId.value}_${problemId.value}_${codeLanguage.value}}`) || '// code here',
    language: 'cpp',
    theme: 'vs-dark',
    lineNumbers: 'on',
    automaticLayout: true, // auto resize
  });
  fetchProblem();
  if (contestId.value) {
    fetchContest();
  }

  setTimeout(() => {
    fetchSubmitHistory();
  }, 1000);
  leftTabsKey.value = PROBLEM_TABS_KEYS.CONTENT;
});

onUnmounted(() => {
  Storage.setLocalItem(`code_${contestId.value}_${problemId.value}_${codeLanguage.value}`, editor.getValue());
  editor.dispose();
});


const problem: Problem = reactive({});
const fetchProblem = async () => {
  let res = null;
  try {
    if (problemNumber.value) {
      res = (await getContestProblem({
        problemNumber: problemNumber.value,
        contestId: contestId.value,
      })) as any;
      // todo: 功能耦合
      problemId.value = res.id;
    } else res = await getProblemById(problemId.value);
    Object.assign(problem, res);
    setProblemContent(res.content.description);
  } catch (e) {
    router.back();
  }
};

const leftTabsKey = ref(PROBLEM_TABS_KEYS.SUBMISSION);
const codeLanguage = ref(CODE_LANGUAGES.CPP);
const handleLanguageChange = (language: string) => {
  const langToText: any = {
    c: 'c',
    cpp: 'cpp',
    jsNode: 'javascript',
  };
  const model = monaco.editor.createModel(editor.getValue(), langToText[language]);
  editor.setModel(model);
};

const submitLoading = ref(false);
const handleCodeSubmit = async () => {
  try {
    submitLoading.value = true;
    const code = editor.getValue();
    const lang = codeLanguage.value;
    if (code === '' || !problemId.value) return;
    let res: any = null;
    if (problemNumber.value) {
      res = await submitContestProblem({
        code,
        problemId: problemId.value,
        lang,
        problemNumber: problemNumber.value,
        contestId: contestId.value,
      });
    } else {
      res = await submit({
        code,
        problemId: problemId.value,
        lang,
      });
    }
    if (res.submissionId) {
      setTimeout(() => {
        fetchSubmitResult(res.submissionId);
      }, 0);
    }
  } catch (e) {
    submitLoading.value = false;
    throw e;
  }

};

const submitList = reactive([]);
const submitRes = ref({});
const fetchSubmitHistory = async () => {
  let list: any = null;
  if (problemNumber.value) {
    list = await getContestSubmissionList({
      contestId: contestId.value,
      problemNumber: problemNumber.value,
    });
  } else {
    list = await getSubmissionList(problemId.value);
  }
  // 最晚提交放在前面
  list.sort((a: any, b: any) => b.createTime - a.createTime);
  submitList.splice(0, submitList.length);
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  submitList.push(...list);
};

const fetchSubmitResult = async (id: string) => {
  let res;
  if (problemNumber.value) {
    res = await getContestSubmissionById({ id });
  } else res = (await getSubmissionById({ id })) as any;
  console.log(res);
  if (res.remote_verdict === 'Submit Failed') {
    message.error('提交失败');
  } else if (res.status !== 'P' || res.remote_verdict === 'Submit Failed') {
    message.success('提交成功');
    submitRes.value = reactive(res.result);
    leftTabsKey.value = PROBLEM_TABS_KEYS.SUBMISSION;
    submitLoading.value = false;
    await fetchSubmitHistory();
  } else {
    await fetchSubmitHistory();
    setTimeout(() => {
      fetchSubmitResult(id);
    }, 5000);
  }
};


const columns = [
  {
    title: '提交结果',
    dataIndex: 'remoteVerdict',
    key: 'remoteVerdict',
    align: 'center',
  },
  {
    title: '耗时',
    dataIndex: 'problemId',
    key: 'time',
    align: 'center',
  },
  {
    title: '内存',
    dataIndex: 'problemId',
    key: 'memory',
    align: 'center',
  },
  {
    title: '语言',
    dataIndex: 'lang',
    key: 'lang',
    align: 'center',
  },
  {
    title: '提交时间',
    dataIndex: 'createTime',
    key: 'createTime',
    align: 'center',
  },
];


</script>
<template>
  <div class="problem-page">
    <Splitpanes class="default-theme">
      <Pane :size="30">
        <div class="problem-page-left">
          <a-tabs v-model:activeKey="leftTabsKey" centered style="height: 100%">
            <a-tab-pane :key="PROBLEM_TABS_KEYS.CONTENT" tab="题目描述" class="container">
              <div class="title">#{{ problem.id + '. ' + problem.title }}</div>
              <div class="limit">时间限制：{{ problem.time_limit }}空间限制：{{ problem.memory_limit }}</div>
              <a-divider></a-divider>
              <h2>题目描述</h2>
              <div class="content" v-html="setProblemContent(problem.content.description)"></div>
              <h2>输入描述</h2>
              <div class="content" v-html="setProblemContent(problem.content.input_description)"></div>
              <h2>输出描述</h2>
              <div class="content" v-html="setProblemContent(problem.content.output_description)"></div>
              <h2>输入输出样例</h2>
              <div>
                <div v-for="(sample, index) in problem.content.samples" :key="index" class="example">
                  <h3>样例 {{ index + 1 }}</h3>
                  <div class="input-output-pair">
                    <div>
                      <span class="input">输入:</span>
                      <button class="copy-button" @click="copyCode(sample.input)">复制</button>
                    </div>
                    <div class="code-container">
                      <pre :id="'input-code-' + index" class="code">{{ sample.input }}</pre>

                    </div>
                  </div>
                  <div class="input-output-pair">
                    <div>
                      <span class="output">输出:</span>
                      <button class="copy-button" @click="copyCode(sample.output)">复制</button>
                    </div>

                    <div class="code-container">
                      <pre :id="'output-code-' + index" class="code">{{ sample.output }}</pre>
                    </div>
                  </div>
                </div>
              </div>
            </a-tab-pane>

            <a-tab-pane :key="PROBLEM_TABS_KEYS.SUBMISSION" class="container" tab="提交记录">
              <SubmitResult v-if="Object.keys(submitRes).length" :result="submitRes"/>
              <SubmitList :list="submitList" :columns="columns"/>
            </a-tab-pane>
          </a-tabs>
        </div>
      </Pane>
      <Pane :size="70" style="height: 100%; min-width: 30%">
        <div class="problem-page-right">
          <div class="tools-top">
            <a-select v-model:value="codeLanguage" size="small" style="width: 150px" @change="handleLanguageChange">
              <a-select-option :value="CODE_LANGUAGES.C">C</a-select-option>
              <a-select-option :value="CODE_LANGUAGES.CPP">C++</a-select-option>
              <a-select-option :value="CODE_LANGUAGES.JS_NODE">Javascript Node</a-select-option>
            </a-select>
          </div>

          <div id="container"/>
          <div class="tools-bottom">
            <span v-if="!canSubmit"
                  style="font-size: 12px; margin: 0 8px; color: #ff6161">不在比赛时间，不能提交</span>
            <a-button type="primary" :loading="submitLoading" :disabled="!canSubmit" @click="handleCodeSubmit">
              提交代码
            </a-button>
          </div>
        </div>
      </Pane>
    </Splitpanes>

  </div>
</template>

<style scoped lang="less">
.problem-page {
  //display: flex;
  //flex-direction: row;
  height: 100%;
  width: 100%;

  &-left {
    //width: 30%;
    height: 100%;
    overflow: hidden;
    border-right: 1px solid #c4c3c3;

    .container {
      padding: 0 16px 20px;
    }

    .title {
      text-align: center;
      font-size: 16px;
      font-weight: 700;
    }

    .limit {
      margin-top: 8px;
      font-size: 12px;
      text-align: center;
    }

    .content {
      font-size: 13px;

      ::v-deep(pre) {
        white-space: pre-wrap;
        background-color: rgba(0, 10, 32, 0.05);
        padding: 10px 15px;
        margin-bottom: 10px;
        color: black;
        line-height: 1.6;
        font-size: 13px;
        border-radius: 3px;
      }
    }

  }

  &-right {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 100%;

    #container {
      flex: 1;
      width: 100%;
    }

    .tools-top {
      display: flex;
      align-items: center;
      height: 32px;
      padding: 0px 20px;
    }

    .tools-bottom {
      display: flex;
      justify-content: right;
      align-items: center;
      height: 56px;
      padding: 0px 20px;
    }
  }

  .example {
    margin-bottom: 30px;
    border: 1px solid #ddd;
    border-radius: 5px;
    overflow: hidden;
    box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
  }

  .example h3 {
    background-color: #f0f0f0;
    color: #333;
    padding: 10px;
    margin: 0;
    border-bottom: 1px solid #ddd;
  }

  .input-output-pair {
    display: flex;
    flex-direction: column;
    padding: 10px;
  }

  .input-output-pair .input,
  .input-output-pair .output {
    font-weight: bold;
    margin-bottom: 5px;
  }

  .input {
    color: #00c853;
  }

  .output {
    color: #ff8f00;
  }

  .pre {
    padding: 10px;
    background-color: #f9f9f9;
    border: 1px solid #ddd;
    border-radius: 5px;
    overflow-x: auto;
  }

  .code {
    font-family: 'Courier New', Courier, monospace;
    font-size: 14px;
    line-height: 1.5;
  }

  .copy-button {
    float: right;
  }

}
</style>

<style>
.problem-page-left .ant-tabs-content-holder,
.problem-page-left .ant-tabs-content,
.problem-page-left .ant-tabs-tabpane {
  height: 100%;
  overflow: auto;
}
</style>


<script lang="ts">
// eslint-disable-next-line import/no-duplicates
import { useToast } from 'vue-toast-notification';
import { defineComponent } from 'vue';
// eslint-disable-next-line import/no-duplicates


const toast = useToast();
export default defineComponent({
  methods: {
    copyCode(code: string) {
      navigator.clipboard.writeText(code).then(() => {
        toast.success('复制成功');
      }).catch(err => {
        console.error('复制失败:', err);
      });
    }
  }
});

</script>
